/**
 * @File name: modules/static_pool.c
 * @Synopsis:
 * @Author: xing.dai@aliyun.com
 * @Version: 0.0.1
 * @Date: 2018-08-28 13:55
 */

#include "static_pool.h"
#include "debug_print.h"
#include "string.h"

#define MAX_LIST_POOL_NUM	10
#define MAX_NODE_POOL_NUM	40
#define MAX_OBJECT_POOL_NUM	40
#define MAX_DEVICE_POOL_NUM	40

#if 1
#define static_pool_dbg2(x_format, ...)	dbg2(x_format, ##__VA_ARGS__)
#else
static_pool_dbg2(x_format, ##args)
#endif

enum {
    POOL_NOT_INIT,
    POOL_NORMAL,
};

typedef struct {
    static_mem_type type;
    char			*name;
    uint16			status;
    uint16			elem_size;
    uint16			total;
    uint16			free;
    uint8			*base_addr;
    uint8			*new_addr;
    uint8			*limit_addr;
} pool_t;


/* Manage pool struct. */
static pool_t	pool_mem[MEM_STATIC_LIMIT_ID];

/* Pool in static memory. */
static list_t	list_pool_mem[MAX_LIST_POOL_NUM];
static node_t	node_pool_mem[MAX_NODE_POOL_NUM];
static object_t	object_pool_mem[MAX_OBJECT_POOL_NUM];
static device_t	device_pool_mem[MAX_DEVICE_POOL_NUM];

static int pool_initial(char *name, static_mem_type type, uint16 size, uint16 total, uint8 *base_addr)
{
    pool_t *pool = &pool_mem[type];

    if (size == 0 || total == 0) {
        dbg0("[%s] \"%s\" failed: size:%d total:%d.\n", __func__, name, size, total);
        return -1;
    }
    pool->type = type;
    pool->elem_size = size;
    pool->total = total;
    pool->free = total;
    pool->status = POOL_NORMAL;
    pool->base_addr = base_addr;
    pool->new_addr = base_addr;
    pool->limit_addr = base_addr + size * total;
    //memset(pool->name, 0, POOL_NAME_MAX);
    //strncpy(pool->name, name, POOL_NAME_MAX - 1);
    pool->name = name;

    dbg2("[%-15s] init type:%-2d st:%-2d es:%-4d t:%-4d f:%-4d base:%p new:%p limit:%p\n",
         pool->name, pool->type, pool->status, pool->elem_size, pool->total, pool->free,
         pool->base_addr, pool->new_addr, pool->limit_addr);
    return 0;
}

static void print_pool(pool_t *pool)
{
    dbg2("[%-15s] type:%-2d st:%-2d es:%-4d t:%-4d f:%-4d base:%p new:%p limit:%p\n",
         pool->name, pool->type, pool->status, pool->elem_size, pool->total, pool->free,
         pool->base_addr, pool->new_addr, pool->limit_addr);
}
/**
 * @Synopsis
 *
 * @Param pool
 *
 * @Returns
 */
static uint8 *pool_alloc(pool_t *pool)
{
    uint8 *alloc_addr;

    if (pool == NULL) {
        dbg0("[%s] arg error.\n", __func__);
        return NULL;
    }
    if (pool->status != POOL_NORMAL) {
        dbg0("[%s] pool(%p) is not initial.\n", __func__, pool);
        return NULL;
    }
    if (pool->new_addr + pool->elem_size >= pool->limit_addr) {
        dbg0("[%s]: pool will overflow.\n");
        print_pool(pool);
        return NULL;
    }
    alloc_addr = pool->new_addr;
    pool->new_addr += pool->elem_size;
    --(pool->free);

    static_pool_dbg2("Alloc ok.[%-15s] type:%-2d st:%-2d es:%-4d t:%-4d f:%-4d base:%p new:%p limit:%p\n",
                     pool->name, pool->type, pool->status, pool->elem_size, pool->total, pool->free,
                     pool->base_addr, pool->new_addr, pool->limit_addr);
    return alloc_addr;
}

void show_pool_detail(void)
{
    uint8 i;
    pool_t *pool = pool_mem;
    show_info("pool_detail:\n");
    show_info("%15s %8s %8s %8s %8s %8s %12s %12s %12s \n",
              "name", "type", "status", "size", "total", "free", "base_addr", "new_addr", "limit_addr");
    for (i = 0; i < MEM_STATIC_LIMIT_ID; i++) {
        show_info("%15s %8d %8d %8d %8d %8d %12p %12p %12p \n",
                  pool->name, pool->type, pool->status, pool->elem_size, pool->total, pool->free,
                  pool->base_addr, pool->new_addr, pool->limit_addr);
        pool++;
    }
    show_info("\n");
}

/**
 * @Synopsis  Public fucntion. Initial pool memory.
 *
 * @Returns
 */
int pool_init(void)
{
    pool_initial("pool_list", MEM_STATIC_LIST_ID, sizeof(list_t), MAX_LIST_POOL_NUM, (uint8 *)list_pool_mem);
    pool_initial("pool_node", MEM_STATIC_NODE_ID, sizeof(node_t), MAX_NODE_POOL_NUM, (uint8 *)node_pool_mem);
    pool_initial("pool_object", MEM_STATIC_OBJECT_ID, sizeof(object_t), MAX_OBJECT_POOL_NUM, (uint8 *)object_pool_mem);
    pool_initial("pool_device", MEM_STATIC_DEVICE_ID, sizeof(device_t), MAX_DEVICE_POOL_NUM, (uint8 *)device_pool_mem);
    show_pool_detail();

    return 0;
}

/**
 * @Synopsis  Alloc buffer in static memory.
 *
 * @Param type
 *
 * @Returns  Alloced buffer address.
 */
void *smalloc(static_mem_type type)
{
    if (type >= MEM_STATIC_LIMIT_ID)
        return NULL;

    return pool_alloc(&pool_mem[type]);
}

